package org.yinweichen.llm_dataset_backend.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.yinweichen.llm_dataset_backend.DTO.CreateTaskRequest;
import org.yinweichen.llm_dataset_backend.DTO.GetTasksResponse;
import org.yinweichen.llm_dataset_backend.DTO.SingleEvalRequest;
import org.yinweichen.llm_dataset_backend.entity.*;
import org.yinweichen.llm_dataset_backend.repository.*;
import org.yinweichen.llm_dataset_backend.service.EvalService;
import org.yinweichen.llm_dataset_backend.service.PointsService;
import org.yinweichen.llm_dataset_backend.util.ModelApiClient;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/eval")
public class EvalController {
    private final EvaluateRepository evaluateRepository;
    private final EvalTaskRepository evalTaskRepository;
    private final LlmAnswerRepository llmAnswerRepository;
    private final StandardAnswerRepository standardAnswerRepository;
    private final PointsService pointsService;
    private final StandardQuestionRepository standardQuestionRepository;
    private final EvalService evalService;

    /**
     * 评测单个LLM答案
     * @param request 评测请求，包括评测任务ID和答案ID，以及使用的prompt
     */
    @Transactional
    @PostMapping("/answer")
    public ResponseEntity<?> evaluateAnswer(@RequestBody SingleEvalRequest request) {
        try {
            // 获取LLMAnswer
            LlmAnswer llmAnswer = llmAnswerRepository.findById(request.answerId())
                    .orElseThrow(() -> new RuntimeException("未找到对应的LLMAnswer"));
            EvalTask evalTask = evalTaskRepository.findById(request.evalTaskId())
                    .orElseThrow(() -> new RuntimeException("未找到对应的EvalTask"));
            StandardQuestion standardQuestion = llmAnswer.getQuestion();
            StandardAnswer standardAnswer = standardAnswerRepository.findById(new StandardAnswerId(standardQuestion.getId(),evalTask.getConfig()))
                    .orElseThrow(() -> new RuntimeException("未找到对应的StandardAnswer"));

            // 构造评测JSON数据
            String jsonData = getJsonData(standardAnswer, standardQuestion, llmAnswer);
            String prompt=evalTask.getPrompt();
            log.info("开始评测请求，prompt: {}, 数据: {}",
                prompt, jsonData);

            // 设置使用gpt-4模型
            ModelApiClient.setCurrModel("gpt-4o");

            // 调用API进行评测
            String evaluationResult = ModelApiClient.getAnswer(prompt,jsonData);

            if (evaluationResult == null) {
                throw new RuntimeException("API调用返回空结果");
            }

            log.info("评测完成，结果长度: {}", evaluationResult.length());


            // 创建Evaluate记录
            Evaluate evaluate = Evaluate.builder()
                    .judge("gpt-4o")
                    .singleReport(evaluationResult)
                    .active(true)
                    .answer(llmAnswer)
                    .build();

            evaluateRepository.save(evaluate);

            return ResponseEntity.ok(evaluationResult);

        } catch (Exception e) {
            log.error("评测过程中发生错误", e);
            return ResponseEntity.internalServerError()
                .body("评测失败: " + e.getMessage());
        }
    }

    @Transactional
    @PostMapping("/task")
    public ResponseEntity<?> createEvalTask(@RequestBody CreateTaskRequest request) {
        try {
            //参数校验
            for(Long questionId : request.questionIds()){
                standardQuestionRepository.findById(new StandardQuestionId(questionId,request.version()))
                        .orElseThrow(() -> new RuntimeException("未找到对应的StandardQuestion"));
            }
            // 生成配置JSON
            Map<String, Object> configMap = new HashMap<>();
            configMap.put("prompt", request.prompt());
            configMap.put("judges", request.judges());
            configMap.put("models", request.models());
            configMap.put("questions", request.questionIds());

            String configJson = new ObjectMapper().writeValueAsString(configMap);

            // 创建评测任务
            EvalTask evalTask = EvalTask.builder()
                    .title(request.title())
                    .description(request.description())
                    .config(configJson)
                    .status("PENDING")
                    .time(new Date())
                    .version(request.version())
                    .build();

            // 保存评测任务
            EvalTask savedTask = evalTaskRepository.save(evalTask);

            return ResponseEntity.ok(savedTask.getId());
        } catch (Exception e) {
            log.error("创建评测任务失败", e);
            return ResponseEntity.internalServerError()
                    .body("创建评测任务失败: " + e.getMessage());
        }
    }

    /**
     * 执行评测任务
     * @param taskId 评测任务ID
     * @return 评测结果
     */
    @PostMapping("/task/{taskId}/run")
    public ResponseEntity<?> runEvaluation(@PathVariable Long taskId) {
        return evalService.runEvaluation(taskId);
    }

    @GetMapping("/tasks")
    public ResponseEntity<List<GetTasksResponse>> getTasks(@RequestParam String version) {
        try {
            List<EvalTask> tasks = evalTaskRepository.findByVersion(version);
            List<GetTasksResponse> responses = tasks.stream()
                .map(GetTasksResponse::fromEvalTask)
                .toList();
            return ResponseEntity.ok(responses);
        } catch (Exception e) {
            log.error("获取评测任务列表失败", e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 获取评测任务下的所有LLM回答
     * @param taskId 评测任务ID
     * @return LLM回答列表
     */
    @Transactional(readOnly = true)
    @GetMapping("/task/{taskId}/answers")
    public ResponseEntity<List<LlmAnswer>> getAnswersByTask(@PathVariable Long taskId) {
        try {
            List<LlmAnswer> answers = llmAnswerRepository.findAllByTaskId(taskId);
            return ResponseEntity.ok(answers);
        } catch (Exception e) {
            log.error("获取评测任务下的回答失败", e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 根据LLM回答ID获取对应的所有评测记录
     * @param answerId LLM回答ID
     * @return 评测记录列表
     */
    @Transactional(readOnly = true)
    @GetMapping("/answer/{answerId}/evaluates")
    public ResponseEntity<List<Evaluate>> getEvaluatesByAnswer(@PathVariable Long answerId) {
        try {
            List<Evaluate> evaluates = evaluateRepository.findAllByAnswerId(answerId);
            return ResponseEntity.ok(evaluates);
        } catch (Exception e) {
            log.error("获取LLM回答的评测记录失败", e);
            return ResponseEntity.internalServerError().build();
        }
    }

    private String getJsonData(StandardAnswer standardAnswer, StandardQuestion standardQuestion, LlmAnswer llmAnswer) {
        StringBuilder keyPointsJson = new StringBuilder();
        ResponseEntity<List<Points>> response = pointsService.getPointsByAnswerId(standardAnswer.getQuestionId(), standardAnswer.getVersion());

        if (response != null && response.getStatusCode().is2xxSuccessful()) {
            response.getBody();
            List<Points> pointsList = response.getBody();
            if (!pointsList.isEmpty()) {
                keyPointsJson.append("\"key_points\": {");
                int index = 1;
                for (Points point : pointsList) {
                    if (point.getActive()) {
                        keyPointsJson.append(String.format("\"%d\": \"%s\"", index++, point.getKeyword()));
                        if (index <= pointsList.size()) {
                            keyPointsJson.append(", ");
                        }
                    }
                }
                keyPointsJson.append("}, ");
            }
        }

        return String.format(
            "{ \"question\": \"%s\", " +
            "\"reference_answer\": \"%s\", " +
            "%s" +
            "\"candidate_answer\": \"%s\" }",
            standardQuestion.getQuestion(),
            standardAnswer.getAnswer(),
            keyPointsJson,
            llmAnswer.getAnswer()
        );
    }
}
